﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using BrainTechLLC;
using ImageAppDataModels;
using ImageAppViewModels;
using System.Collections.Generic;

namespace WpfImageDuplicates
{
    public class ThumbnailCleanup : BaseNotifyPropertyChanged
    {
        public DateTime LastCleaned = DateTime.MinValue;
        public DateTime LastCheckCleaned = DateTime.MinValue;
        protected bool _go;
        protected bool _wantExit;
        protected bool _checkCollectionCleanup;
        protected Thread _thread;
        protected object _lockObject = new object();
        private int _cleanCycle;
        private bool _needsClean;
        private bool _runningCleanCycle = false;
        protected ThumbnailImageCollectionHandler _thumbHandler;

        public ThumbnailCleanup(ThumbnailImageCollectionHandler thumbHandler)
        {
            _thumbHandler = thumbHandler;
        }

        public void MarkNeedsClean()
        {
            _needsClean = true;
        }

        public void DoTheCleanupWorker()
        {
            while (true)
            {
                DateTime now = DateTime.Now;

                if (_wantExit)
                {
                    return;
                }
                while (_runningCleanCycle)
                {
                    Thread.Sleep(100);
                }

                if (LastCheckCleaned.AddSeconds(10) > now || (!_go && !_checkCollectionCleanup))
                {
                    Thread.Sleep(50);
                    continue;
                }

                if (LastCheckCleaned.AddSeconds(5) < now)
                {
                    Thread.Sleep(100);
                }

                if (LastCheckCleaned.AddSeconds(5) < now && _go)
                {
                    _runningCleanCycle = true;
                    _go = false;

                    if (Application.Current == null)
                    {
                        return;
                    }

                    if (_thumbHandler.CollectionViewModel != null && _thumbHandler.CollectionViewModel != null && _thumbHandler.CollectionViewModel.CachedThumbnailImageSources > Settings.Values.MaxThumbnailImageSources)
                    {
                        _thumbHandler.CollectionViewModel.ClearCachedThumbnailImageSources(Settings.Values.MaxThumbnailImageSources / 2);
                    }

                    try
                    {
                        long loadedBitmapBytes = 0;
                        // collect basic stats about the collection and what is loaded
                        if (_thumbHandler.CollectionViewModel != null && _thumbHandler.CollectionViewModel.ImageCollection != null)
                        {
                            var count = _thumbHandler.CollectionViewModel.ImageCollection.GetCounts();
                            loadedBitmapBytes = count.LoadedBitmapBytes;

                            for (int n = 0; n < _thumbHandler.CollectionViewModel.ImageCollection.Count; n++)
                            {
                                var fi = _thumbHandler.CollectionViewModel.ImageCollection[n];                                

                                if (fi.BitmapCached != null || (fi as FileImage).TransformedBitmapCached != null || fi.ImageSourceCached != null)
                                {
                                    if (Window1.MainWindow._FullViewerHandler.IsLoaded)
                                    {
                                        var fullViewerHandler = Window1.MainWindow._FullViewerHandler;

                                        if (fullViewerHandler != null && fullViewerHandler.Handler.BitmapPreloader != null)
                                        {
                                            var vmFull = Window1.MainWindow._FullViewerHandler.Handler.ImageViewModel;
                                            if (vmFull != null)
                                            {
                                                if (fi != vmFull.FileImage)
                                                {
                                                    if (fullViewerHandler.Handler.BitmapPreloader._working != null)
                                                    {
                                                        List<FileImageViewModel> viewModels = new List<FileImageViewModel>();
                                                        List<FileImage> fileImages = new List<FileImage>();
                                                        for (int b = 0; b < fullViewerHandler.Handler.BitmapPreloader._working.Count; b++)
                                                        {
                                                            FileImageViewModel vm = fullViewerHandler.Handler.BitmapPreloader._working[b] as FileImageViewModel;
                                                            if (vm != null)
                                                            {
                                                                viewModels.Add(vm);
                                                            }
                                                            else
                                                            {
                                                                FileImage fileImg = fullViewerHandler.Handler.BitmapPreloader._working[b] as FileImage;
                                                                fileImages.Add(fileImg);
                                                            }
                                                        }
                                                        var found = viewModels.FirstOrDefault(f => f.FileImage == fi);
                                                        if (found == null)
                                                        {
                                                            var found2 = fileImages.FirstOrDefault(fimg => fimg == (fi as FileImage));

                                                            if (found2 == null)
                                                            {
                                                                fi.BitmapCached = null;
                                                                (fi as FileImage).TransformedBitmap = null;
                                                                fi.ImageSource = null;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        Dispatcher dispatch = Application.Current.Dispatcher;

                        _runningCleanCycle = true;
                        var all = _thumbHandler.CollectionViewModel;
                        int additionalInfos = -1;

                        if (all != null)
                        {
                            for (int n = all.Count - 1; n >= 0; n--)
                            {
                                var item = all[n];

                                if (item != null)
                                {
                                    if (!item.ThumbVisible)
                                    {
                                        item.UpdateIfDirty(false, false);
                                        //if (item != null && item.ThumbnailObject != null)
                                        //{                                            
                                        //    item.ClearThumbnail();
                                        //    item.ThumbnailObject = null;
                                        //}

                                        if (item.FileImage.ImageInfoCached != null)
                                        {
                                            if (additionalInfos == -1)
                                            {
                                                additionalInfos = all.Count((thumbView) => thumbView.FileImage.ImageInfoCached != null);
                                            }

                                            // TODO - make this a setting
                                            if (additionalInfos > 30)
                                            {
                                                item.FileImage.ClearImageInfo();
                                                additionalInfos--;
                                            }
                                        }

                                        if (item.Item.ImageBytesCached != null || item.BitmapLoaded || item._hasBeenVisible)
                                        {
                                            item._hasBeenVisible = false;

                                            //if (dispatch != null)
                                            //{
                                            //    dispatch.BeginInvoke(new OneParamDelegate((o) =>
                                            //    {
                                            //        try
                                            //        {
                                            //            ThumbnailView vw = o as ThumbnailView;
                                            //            vw.UpdateIfDirty(vw.ThumbVisible, false);
                                            //        }
                                            //        catch (Exception ex)
                                            //        {
                                            //            Console.WriteLine(ex.ToString());
                                            //        }
                                            //    }),
                                            //    DispatcherPriority.ApplicationIdle,
                                            //    item);
                                            //}
                                            //else
                                            //{
                                            //    item.UpdateIfDirty(item.ThumbVisible, false);
                                            //}
                                        }

                                        if (n % 20 == 19)
                                        {
                                            Thread.Sleep(2);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }

                    LastCheckCleaned = DateTime.Now;

                    // TODO: Move these?
                    _cleanCycle = 0;
                    _needsClean = false;
                }

                if (_checkCollectionCleanup)
                {
                    _checkCollectionCleanup = false;
                    if (_thumbHandler.CollectionViewModel != null)
                    {
                        _thumbHandler.CollectionViewModel.CheckCleanup();
                    }
                    _thumbHandler.ThumbCleanup.LastCleaned = DateTime.Now;
                }

                _runningCleanCycle = false;
            }
        }

        public void CheckInit()
        {
            if (_thread == null)
            {
                lock (_lockObject)
                {
                    if (_thread == null)
                    {
                        ThreadStart ts = new ThreadStart(DoTheCleanupWorker);
                        _thread = ts.CreateAndRunThread(true);
                        _thread.Name = "ThumbnailCleanup";
                        _thread.Priority = ThreadPriority.Normal; // was belownormal
                    }
                }
            }
        }

        public void HandleCleanupCollection()
        {
            CheckInit();

            if (DateTime.Now.AddSeconds(-20) > _thumbHandler.ThumbCleanup.LastCleaned)
            {
                _thumbHandler.ThumbCleanup.LastCleaned = DateTime.Now;
                _checkCollectionCleanup = true;
            }
        }

        public void HandleCleanCycle()
        {
            if (_needsClean)
            {
                _cleanCycle++;

                if (!_go && _cleanCycle == 40)
                {
                    CheckInit();
                    _go = true;
                    _checkCollectionCleanup = true;
                    _cleanCycle = 0;
                }
            }
        }

        internal void Stop()
        {
            _wantExit = true;
        }
    }

}
